﻿namespace ToRTalent {
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using Talents;

    public partial class TalentButton : UserControl {
        /// <summary>
        /// Initializes a new instance of the TalentButton control
        /// </summary>
        public TalentButton() {
            InitializeComponent();
        }

        /// <summary>
        /// Pointer to the TalentPanel control where this control resides
        /// </summary>
        internal TalentPanel TalentPanel { get { return ( TalentPanel )( ( ( Grid )Parent ).Parent ); } }

        // Encapsulated variable that represents the TalentDataAttribute for this control
        private TalentDataAttribute talentData;

        /// <summary>
        /// Gets or sets the TalentDataAttribute for the this control
        /// </summary>
        internal TalentDataAttribute TalentData {
            get { return talentData; }
            set {
                talentData = value;
                current = talentData == null ? 0 : ( int )Math.Min( TalentPanel.CharacterTalents.PointsSpent[talentData.Index], talentData.MaxPoints );
            }
        }
        
        // Encapsulated variable that represents the the points spent on this talent
        private int current;

        /// <summary>
        /// Gets or sets a value that represents the the points spent on this talent
        /// </summary>
        internal int Current {
            get { return current; }
            set {
                if( talentData != null && value >= 0 && value <= talentData.MaxPoints && CanPutPoints ) {
                    MainPage.PtsAvailable = value < current ? MainPage.PtsAvailable + 1 : MainPage.PtsAvailable - 1;
                    current = value;
                    TalentPanel.CharacterTalents.PointsSpent[TalentData.Index] = current;
                    TalentPanel.RankChanged();
                }
            }
        }

        /// <summary>
        /// Gets a bool value indicating if the points spent in this talent
        /// is equal to the MaxPoints of the talent
        /// </summary>
        internal bool IsMaxRank {
            get { return current == talentData.MaxPoints; }
        }

        /// <summary>
        /// A basic check to see if you are within the bounds or available points
        /// </summary>
        /// <param name="isDecrement">Value indicating if you are decrementing</param>
        /// <returns>A value indicating if you are within the acceptable range</returns>
        internal bool IsBelowAboveMax( bool isDecrement ) {
            return isDecrement ? ( MainPage.PtsAvailable - 1 ) >= 0 : ( MainPage.PtsAvailable + 1 ) <= 41;
        }

        /// <summary>
        /// Uses a whole lot of logical operators to determine if you can spent points in this talent
        /// To many things to check but...what are you going to do
        /// </summary>
        /// <returns></returns>
        internal bool CanPutPoints {
            get {
                return TalentPanel.GetPointsBelowRow( talentData.Row ) >= ( talentData.Row - 1 ) * 5 &&
                                ( talentData.Prerquisite < 0 ||
                                TalentPanel.CharacterTalents.PointsSpent[talentData.Prerquisite] == TalentPanel.GetAttribute( talentData.Prerquisite ).MaxPoints )
                    /*&& TalentTab.PtsAvailable > 0*/;
            }
        }

        // Border image of a talent that provides an ability
        private BitmapImage ABILITY = new BitmapImage( new Uri( @"Images/TalentCalc/TalentBtnGreen.png", UriKind.Relative ) );

        // Border image of a talent that provides an ability with max points spent
        private BitmapImage ABILITY_MAX = new BitmapImage( new Uri( @"Images/TalentCalc/TalentBtnGreenGold.png", UriKind.Relative ) );

        // Border image of a talent that is currently disabled
        private BitmapImage DISABLED = new BitmapImage( new Uri( @"Images/TalentCalc/TalentBtnGray.png", UriKind.Relative ) );

        // Border image of a normal talent
        private BitmapImage NORMAL = new BitmapImage( new Uri( @"Images/TalentCalc/TalentBtnBlue.png", UriKind.Relative ) );

        // Border image of a normal talent with max points spent
        private BitmapImage NORMAL_MAX = new BitmapImage( new Uri( @"Images/TalentCalc/TalentBtnBlueGold.png", UriKind.Relative ) );

        // Talent icon path. Wont be needed when I finish implementing the talent icon sprite
        private const string ICON_PREFIX = @"Images/TalentIcons/";

        /// <summary>
        /// Updates all aspects of the control depending on points spent in talent
        /// and the max points. Changes border, overlay, and labels
        /// </summary>
        internal void Update() {
            if( talentData != null ) {
                if( Current == talentData.MaxPoints ) {
                    OverlayImg.Source = talentData.IsAbility ? ABILITY_MAX : NORMAL_MAX;

                    RankTxt.Foreground = new SolidColorBrush( Colors.Black );
                    RankTxt.Text = string.Format( "{0}", talentData.MaxPoints );
                    FadeRec.Visibility = Visibility.Collapsed;
                }

                else {
                    if( CanPutPoints && ( MainPage.PtsAvailable > 0 || Current > 0 ) ) {
                        OverlayImg.Source = talentData.IsAbility ? ABILITY : NORMAL;
                        FadeRec.Visibility = Visibility.Collapsed;
                    }

                    else {
                        OverlayImg.Source = DISABLED;
                        FadeRec.Visibility = Visibility.Visible;
                    }

                    RankTxt.Foreground = new SolidColorBrush( Colors.White );
                    RankTxt.Text = string.Format( "{0}  {1}", Current, talentData.MaxPoints );
                }

                // Set talent icon from sprite
                TranslateTransform offsetTransform = new TranslateTransform();
                imgBrush.ImageSource = new BitmapImage( new Uri( ICON_PREFIX + MainPage.MainTalents.TalentIcon, UriKind.Relative ) );
                offsetTransform.X = TalentXY[0];
                offsetTransform.Y = TalentXY[1];
                imgBrush.Transform = offsetTransform;

                // Set talent tooltip
                ToolTipService.SetToolTip( this, GetTooltipString() );
                this.Visibility = Visibility.Visible;
            }

            else {
                this.Visibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// Formats the string to be used on the talent tool-tip
        /// </summary>
        /// <returns>A talent tool-tip string</returns>
        public string GetTooltipString() {
            string n = talentData.Name + "\n\n";

            if( Current == 0 ) {
                return string.Format( n + "Next Rank:\n{0}", WrapText( talentData.Description[0] ) );
            }

            return Current == talentData.MaxPoints ?
                string.Format( n + "{0}", WrapText( talentData.Description[talentData.MaxPoints - 1] ) ) :
                string.Format( n + "{0}\n\nNext Rank:\n{1}", WrapText( talentData.Description[Current - 1] ), WrapText( talentData.Description[Current] ) );
        }

        /// <summary>
        /// Creates a string that is wrapped at a set width of characters
        /// </summary>
        /// <param name="toWrap">The string to be wrapped</param>
        /// <param name="wrapWidth">Optional: Width to wrap text at. Default is 63</param>
        /// <returns>A wrapped string</returns>
        private static string WrapText( string toWrap , int wrapWidth = 63) {
            if( toWrap.Length <= wrapWidth )
                return toWrap; // Don't bother wrapping

            bool eos = false;
            bool foundspace = false;
            int i = wrapWidth;
            string retVal = toWrap;

            while( !eos ) {
                while( !foundspace && i >= 0 ) {
                    if( retVal[i] == ' ' ) {
                        foundspace = true;
                        break;
                    }

                    i--; // didn't find a space so backtrack a char
                }

                if( foundspace ) {
                    retVal = retVal.Insert( i + 1, "\r\n" ); // +1 because we want it after the space
                    i++;
                    foundspace = false;
                }

                // Continue to next part of string unless we're at or close to the end
                if( i + wrapWidth >= retVal.Length - 1 )
                    eos = true;
                else
                    i += wrapWidth;
            }

            return retVal;
        }

        /// <summary>
        /// Event handler for when this control receives a click event
        /// </summary>
        private void TalentClicked( object sender, MouseButtonEventArgs e ) {
            if((Keyboard.Modifiers & ModifierKeys.Shift) == 0) {
                if( MainPage.PtsAvailable > 0 )
                    Current++;
            }

            else {
                if( MainPage.PtsAvailable < 41 )
                    Current--;
            }
        }

        /// <summary>
        /// Gets the X and Y coordinates of the this talent's icon from the
        /// icon sprite of this advance class
        /// </summary>
        private int[] TalentXY {
            get {
                int icoDimension = 50; // Current icon size
                int xCoord = 0;
                int yCoord = 0;

                if( talentData.Index <= 9 ) {
                    xCoord = -( icoDimension * talentData.Index );
                }

                else {
                    xCoord = -( talentData.Index % 10 ) * icoDimension; // Get the ones digit
                    yCoord = -( talentData.Index / 10 ) * icoDimension; // Get the tens digit
                }

                return new int[2] { xCoord, yCoord };
            }
        }
    }
}
